package com.gorillalogic.scrummonkey.test {
	import com.gorillalogic.scrummonkey.dms.DmsUtils;
	import com.gorillalogic.scrummonkey.dms.Project;
	import com.gorillalogic.scrummonkey.dms.ProjectService;
	import com.gorillalogic.scrummonkey.dms.Release;
	import com.gorillalogic.scrummonkey.dms.ReleaseService;
	
	import mx.collections.ArrayCollection;
	
	import org.flexunit.Assert;
	import org.hamcrest.assertThat;
	import org.hamcrest.collection.everyItem;
	import org.hamcrest.collection.hasItems;
	import org.hamcrest.object.equalTo;

	/**
	 * Create simple hierarchy, initiate Data Management, then create a Release
	 */
	public class ReleaseTest3 extends BaseTest {

		/**
		 * Create hierarchy: P,R
		 */
		[Test(async,order=1)]
		public function create():void {
			var p:Project = new Project('proj1');
			var r1:Release = new Release('rel1');

			//wireup release to project
			p.releases.addItem(r1);
			r1.project = p;

			callAndThenOrFault(ProjectService.service.createProject(p), create2, null, 5000);
		}

		private function create2(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), create3);
		}

		private function create3(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			//verify release
			Assert.assertEquals('Bad number of releases', 1, project.releases.length);
			var release:Release = project.releases.getItemAt(0) as Release;
			Assert.assertTrue('Bad release name', 'rel1', release.name);
			Assert.assertEquals("Bad release's project name", 'proj1', release.project.name);
		}


		/**
		 * Create R under data managed hierarchy.
		 */
		[Test(async,order=2)]
		public function createRelease():void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), createRelease2);
		}

		private function createRelease2(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			var r2:Release = new Release('rel2');

			//Normally, we can just call these operations and forget about it,
			//but if we must guarantee completion...then use a transaction
			callAndThenOrFault(DmsUtils.doTxn(ProjectService.service,
				function ():void {
					r2.project = project;
					//project.releases.addItem(r2);
					ReleaseService.service.createRelease(r2);
				}), createRelease3);
		}

		private function createRelease3(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), createRelease4);
		}

		private function createRelease4(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			//verify releases
			Assert.assertEquals('Bad number of releases', 2, project.releases.length);
			var r1:Release = project.releases.getItemAt(0) as Release;
			var r2:Release = project.releases.getItemAt(1) as Release;
			assertThat('Bad release names', [r1.name,r2.name], hasItems('rel1', 'rel2'));
			assertThat("Bad release's project name", [r1.project.name,r2.project.name], everyItem(equalTo('proj1')));
		}


		/**
		 * Cleanup everything
		 */
		[Test(async,order=3)]
		public function cleanup():void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), cleanup2);
		}

		private function cleanup2(data:Object, passThroughData:Object):void {
			var project:Project = (data.result as ArrayCollection).getItemAt(0) as Project;
			Assert.assertEquals('Bad project name', 'proj1', project.name);

			callAndThenOrFault(ProjectService.service.deleteProject(project), cleanup3);
		}

		private function cleanup3(data:Object, passThroughData:Object):void {
			callAndThenOrFault(ProjectService.service.getByName('proj1'), cleanup4, null, 5000, 'proj1');
			callAndThenOrFault(ReleaseService.service.getByName('rel1'), cleanup4, null, 5000, 'rel1');
			callAndThenOrFault(ReleaseService.service.getByName('rel2'), cleanup4, null, 5000, 'rel2');
		}
		
		private function cleanup4(data:Object, passThroughData:Object):void {
			var entities:ArrayCollection = data.result as ArrayCollection;
			Assert.assertEquals('Cleanup failed on "' + passThroughData.toString() + '"', 0, entities.length);
		}
	}
}